import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.basic.Action;
import jade.content.onto.basic.Result;
import jade.core.AID;
import jade.core.Agent;
import jade.core.Location;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.ParallelBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.JADEAgentManagement.KillAgent;
import jade.domain.JADEAgentManagement.QueryPlatformLocationsAction;
import jade.domain.mobility.CloneAction;
import jade.domain.mobility.MobileAgentDescription;
import jade.domain.mobility.MobilityOntology;
import jade.domain.mobility.MoveAction;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;
import jade.wrapper.ControllerException;

public class ProfilerAgent extends Agent {

	ArrayList<AID> curatorAgent = new ArrayList<AID>();
	jade.core.Runtime runtime = jade.core.Runtime.instance();
	private String keyword;
	private Map<String, Location> locations = new HashMap<String, Location>();
	private Location destination;

	protected void setup() {

		doWait(500);
		// Register language and ontology
		getContentManager().registerLanguage(new SLCodec());
		getContentManager().registerOntology(MobilityOntology.getInstance());

		System.out.println("CLONE!" + getLocalName());

		findLocation();

		addBehaviour(new ReceiveCommands(this));
		
		createCloneAndMove(getAID(), "Container-1", 1);
		createCloneAndMove(getAID(), "Container-2", 1);

	}

	private void createCloneAndMove(AID aid, String destName, int id) {
		// set location
		Location dest = (Location) locations.get(destName);

		// set mobile agent description
		MobileAgentDescription mad = new MobileAgentDescription();
		mad.setName(aid);
		mad.setDestination(dest);
		CloneAction ca = new CloneAction();
		ca.setNewName("Clone-" + aid.getLocalName() + id);
		ca.setMobileAgentDescription(mad);

		// sends a request about making a new copy of this agent
		sendRequest(new Action(getAID(), ca));
	}

	private void findLocation() {

		try {
			// Get available locations with AMS
			sendRequest(new Action(getAMS(), new QueryPlatformLocationsAction()));

			// Receive response from AMS
			MessageTemplate mt = MessageTemplate.and(
					MessageTemplate.MatchSender(getAMS()),
					MessageTemplate.MatchPerformative(ACLMessage.INFORM));
			ACLMessage resp = blockingReceive(mt);

			// Get locations from AMS from contentmanager
			ContentElement ce = getContentManager().extractContent(resp);
			Result result = (Result) ce;
			jade.util.leap.Iterator it = result.getItems().iterator();

			// add locationname to our hashmap
			while (it.hasNext()) {
				Location loc = (Location) it.next();
				locations.put(loc.getName(), loc);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void sendRequest(Action action) {
		// TODO Auto-generated method stub

		ACLMessage request = new ACLMessage(ACLMessage.REQUEST);
		request.setLanguage(new SLCodec().getName());
		request.setOntology(MobilityOntology.getInstance().getName());
		try {
			getContentManager().fillContent(request, action);
			request.addReceiver(action.getActor());
			send(request);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	protected void afterClone() {
		init();

	}

	class ReceiveCommands extends CyclicBehaviour {
		// -----------------------------------------------

		// private Location destination;

		ReceiveCommands(Agent a) {
			super(a);
		}

		public void action() {
			// Register language and ontology
			getContentManager().registerLanguage(new SLCodec());
			getContentManager()
					.registerOntology(MobilityOntology.getInstance());

			ACLMessage msg = receive(MessageTemplate
					.MatchPerformative(ACLMessage.REQUEST));

			if (msg == null) {
				block();
				return;
			}
			System.out.println(msg);

			if (msg.getPerformative() == ACLMessage.REQUEST) {

				try {
					ContentElement content = getContentManager()
							.extractContent(msg);
					Concept concept = ((Action) content).getAction();

					if (concept instanceof CloneAction) {

						CloneAction ca = (CloneAction) concept;
						String newName = ca.getNewName();
						Location l = ca.getMobileAgentDescription()
								.getDestination();
						if (l != null)
							destination = l;
						doClone(destination, newName);
					} else if (concept instanceof MoveAction) {

						MoveAction ma = (MoveAction) concept;
						Location l = ma.getMobileAgentDescription()
								.getDestination();
						if (l != null)
							doMove(destination = l);
					} else if (concept instanceof KillAgent) {

						doDelete();
					}
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			} else {
				System.out.println("Unexpected msg from controller agent");
			}
		}
	}

	// class MobileAgent
	protected void init() {
		// Register language and ontology
		getContentManager().registerLanguage(new SLCodec());
		getContentManager().registerOntology(MobilityOntology.getInstance());

		System.out.println("Hallo! Profile agent " + getLocalName()
				+ " is here.");

		curatorAgent.add(new AID("Seller", AID.ISLOCALNAME));

		ParallelBehaviour pb = new ParallelBehaviour();
		addBehaviour(new ReceiveCommands(this));
		addBehaviour(new Subscriber());
		addBehaviour(pb);
	}
	private class Subscriber extends OneShotBehaviour {

		public void action() {

			// TODO Auto-generated method stub
			ACLMessage msg = new ACLMessage(ACLMessage.SUBSCRIBE);
			msg.addReceiver(curatorAgent.get(0));
			System.out.println("SHAHALABARRRA!");
			send(msg);
			addBehaviour(new Bidder());

		}
	}

	private class Bidder extends CyclicBehaviour {

		public void action() {

			// bidders informed in the beginning
			MessageTemplate msg = MessageTemplate
					.MatchPerformative(ACLMessage.INFORM);
			ACLMessage informmsg = receive(msg);

			// auctioneer gives price

			MessageTemplate mt = MessageTemplate
					.MatchPerformative(ACLMessage.CFP);
			ACLMessage cfpmsg = blockingReceive(mt);
			if (cfpmsg != null) {
				// Message received. Process it
				keyword = cfpmsg.getContent();
				try {
					if (((Thingy) cfpmsg.getContentObject()).price < 200) {
						ACLMessage reply = cfpmsg.createReply();
						reply.setPerformative(ACLMessage.PROPOSE);

						send(reply);
						System.out.println(getLocalName() + " wants to bid "
								+ keyword);
					} else {
						System.err.println("too expensive!!");
					}
				} catch (UnreadableException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();

				}
				// accept/reject
				if (cfpmsg.getPerformative() == ACLMessage.ACCEPT_PROPOSAL) {
					MessageTemplate mtacc = MessageTemplate
							.MatchPerformative(ACLMessage.ACCEPT_PROPOSAL);
					ACLMessage accmsg = receive(mtacc);
					System.out.print(getLocalName() + " won ");
				}

				else if (cfpmsg.getPerformative() == ACLMessage.REJECT_PROPOSAL) {
					MessageTemplate mtrej = MessageTemplate
							.MatchPerformative(ACLMessage.REJECT_PROPOSAL);
					ACLMessage rejmsg = receive(mtrej);
					System.out.print(getLocalName() + " lost ");
				}

				// no more bidding
				else if (cfpmsg.getPerformative() == ACLMessage.INFORM) {
					MessageTemplate msgend = MessageTemplate
							.MatchPerformative(ACLMessage.INFORM);
					ACLMessage endmsg = blockingReceive(msgend);
					System.out.println("no more bids");
				}

			} else {
				keyword = cfpmsg.getContent();
				ACLMessage reply = cfpmsg.createReply();
				reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
				System.out.println(getLocalName() + " did not understand!");
			}

		}
	}

}
